#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <iterator>
#include <ostream>
#include <string>
#include <unordered_map>
#include <vector>

#include "analyzer.h"
#include "armfunction.h"
#include "armgen.h"
#include "astprinter.h"
#include "dce.h"
#include "irbuilder.h"
#include "irprinter.h"
#include "irtest.h"
#include "lexer.h"
#include "parser.h"
#include "pass.h"
#include "preprocessor.h"
#include "semantics.h"
#include "ssabuilder.h"
#include "ssadestructor.h"
#include "symbol.h"
#include "utils.h"

using namespace Utils;

//#define LOCAL
//

std::string read(std::string path) {
    std::string ret;
#ifdef LOCAL
    path = "../.tests/" + path;
#else
    path = path;
#endif
    freopen(path.c_str(), "r", stdin);
    for (int c; (c = getchar()) != EOF;) ret += char(c);
    return ret;
}

void InitPassManager(PassManager& mgr) {
    // frontend
    mgr.AddPass<Lexer>();
    mgr.AddPass<Preprocessor>();
    mgr.AddPass<Parser>();
    // mgr.AddPass<ASTPrinter>();
    mgr.AddPass<SemanticAnalyzer>(std::vector<ExtFunction>{
        {"_sysy_starttime", 'v', "i"},
        {"_sysy_stoptime", 'v', "i"},
        {"getint", 'i', ""},
        {"getch", 'i', ""},
        {"getfloat", 'f', ""},
        {"getarray", 'i', "I"},
        {"getfarray", 'i', "F"},
        {"putint", 'v', "i"},
        {"putch", 'v', "i"},
        {"putfloat", 'v', "f"},
        {"putarray", 'v', "iI"},
        {"putfarray", 'v', "iF"},
        {"putf", 'v', "..."},
    });
    // mgr.AddPass<SemanticPrinter>();

    // ir
    mgr.AddPass<IRBuilder>();
    // mgr.AddPass<IRPrinter>();

    // optimizer
    // mgr.AddPass<SSABuilder>();
    // mgr.AddPass<DeadCodeEliminator>();
    // mgr.AddPass<SSADestructor>();
    // mgr.AddPass<IRPrinter>();

    // test
    // mgr.AddPass<IRTest>(read(fileName + ".in"));

    // arm
    mgr.AddPass<ArmGenerator>();
}

int online(int argc, char* argv[]) {
    // compiler -S -o out.s in.sy
    std::ofstream ofs(argv[3]);
    std::string text = read(argv[4]);

    PassManager mgr;
    InitPassManager(mgr);

    auto output = mgr.Run(&text);
    auto program = (ArmProgram*)output;

    program->GenAsm(ofs);
    return 0;
}

int local(const std::string& fileName) {
    std::system("clear");
    for (int i = 0; i < 16; ++i) {
        std::cout << Color(i) << i << ' ';
    }
    std::cout << DEF << std::endl;
    Utils::Splitter();
    std::string text = read(fileName + ".sy");

    PassManager mgr;
    InitPassManager(mgr);

    auto output = mgr.Run(&text);
    auto program = (ArmProgram*)output;
    program->Print();

    std::cout << DEF "\n\n";
    return 0;
}

int main(int argc, char* argv[]) {
#ifdef LOCAL
    local("95_float");
#else
    online(argc, argv);
#endif
}
